home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / win_m_p / mews11.zip / MSWMEM.C < prev    next >
C/C++ Source or Header  |  1992-07-01  |  11KB  |  385 lines

  1. /* The routines in this file provide memory allocation under the
  2.    Microsoft Windows environment on an IBM-PC or compatible computer.
  3.  
  4.    Must be compiled with Borland C++ 2.0 or later version.
  5.  
  6.    It should not be compiled if the WINDOW_MSWIN symbol is not set */
  7.  
  8. /* this module allocates memory by performing subsegment allocation from
  9.    a list of global segments. This technique is inspired by an article
  10.    by Paul Yao in Microsoft Systems Journal (January 1991) */
  11.  
  12. #include    "estruct.h"
  13. #include    <stdio.h>
  14. #include    "eproto.h"
  15. #include    "edef.h"
  16. #include    "elang.h"
  17.  
  18. #include    "mswin.h"
  19.  
  20. #if SUBALLOC
  21. #ifdef  malloc
  22. #undef  malloc
  23. #endif
  24. #ifdef  free
  25. #undef  free
  26. #endif
  27. #ifdef  realloc
  28. #undef  realloc
  29. #endif
  30.  
  31. #define SEGHEADOFFSET 16    /* offset of the segment header (the first
  32.                    16 bytes of a heap segment are reserved
  33.                    for windows) */
  34. #define HEAPOFFSET  (SEGHEADOFFSET +  sizeof(SEGHEADER))
  35. #define HEAPOVH     0x400      /* estimated heap overhead */
  36. #define MINSEGSIZE  0x1000L /* minimum segment allocation: 4K */
  37.  
  38. /* Data segment switching macroes. The wS argument MUST be a stack
  39.    variable */
  40. #define SWITCH_DS(wS) asm {push ds; mov ax,wS; mov ds,ax;}
  41. #define RESTORE_DS    asm {pop ds;}
  42.  
  43. typedef struct  SegHeader {     /* segment header */
  44.     struct SegHeader *next;         /* link to next segment header */
  45.     int     alloc_count;            /* number of allocated blocks */
  46. } SEGHEADER;
  47.  
  48. static SEGHEADER SegList = {NULL, -1};/* list of segments (dummy header) */
  49. static SEGHEADER *OptimumSeg = NULL;
  50.  
  51. static BOOL FarStorage = FALSE; /* validates the use of suballocation */
  52.  
  53. #if MEMTRACE
  54. static  unsigned char mtrx = 0;
  55. static  struct mtr_tag {
  56.     WORD    m_func;         /* ASCII signature of function */
  57.     union   {
  58.         WORD    m_wseg;     /* segment selector */
  59.         void    *m_block;   /* block address */
  60.         SEGHEADER *m_segh;  /* segment header */
  61.     } m_ptr;
  62.     WORD    m_cnt;          /* alloc count */
  63.     DWORD   m_size;         /* size of segment or block */
  64.     SEGHEADER *m_optimseg;  /* value of OptimumSeg */
  65. } mtr [256];
  66.  
  67. /* m_func values ... */
  68. #define MTR_SUBALLOC    'SU'
  69. #define MTR_MALLOC      'MA'
  70. #define MTR_MALLOCSEG   'MS'
  71. #define MTR_FREE        'FR'
  72. #define MTR_FREESEG     'FS'
  73. #define MTR_REALLOC     'RA'
  74. #endif
  75.  
  76. /* SubAlloc:    performs suballocation from a global segment */
  77. /* ========                                                  */
  78.  
  79. void * SubAlloc (WORD wSeg, unsigned size)
  80.  
  81. /* wSeg is the global segment's selector */
  82. {
  83.     HANDLE  hBlock;     /* better be a stack variable */
  84.     void    *Block;     /* better be a stack variable */
  85. #if MEMTRACE
  86.     WORD    RealSize = 0;/* better be a stack variable */
  87. #endif
  88.     SWITCH_DS(wSeg)
  89.     hBlock = LocalAlloc (LMEM_FIXED | LMEM_NOCOMPACT, size);
  90.     /* no point attempting compaction: everything is FIXED
  91.        in this heap! */
  92.     if (hBlock) {
  93.     Block = (void*)(LPSTR)LocalLock (hBlock);
  94. #if MEMTRACE
  95.     RealSize = LocalSize (hBlock);
  96. #endif
  97.     }
  98.     RESTORE_DS
  99. #if MEMTRACE
  100.     mtr[mtrx].m_func = MTR_SUBALLOC;
  101.     mtr[mtrx].m_ptr.m_block = hBlock ? Block : NULL;
  102.     mtr[mtrx].m_size = RealSize;
  103.     mtr[mtrx++].m_optimseg = OptimumSeg;
  104. #endif
  105.     if (hBlock) return Block;       /* success ! */
  106.     else return NULL;               /* failure!! */
  107. } /* SubAlloc */
  108.  
  109. /* malloc:  allocates a chunk of memory */
  110. /* ======                               */
  111.  
  112. void * CDECL malloc(size_t size)
  113. {
  114.     SEGHEADER *Seg;         /* segment header pointer */
  115.     WORD    wSeg;           /* segment's selector, must be a stack variable */
  116.     BOOL    NewSeg = FALSE; /* TRUE: a new segment has been allocated */
  117.     void    *Block;         /* obtained block's address */
  118.  
  119. #if MEMTRACE
  120.     mtr[mtrx].m_func = MTR_MALLOC;
  121.     mtr[mtrx].m_ptr.m_block = NULL;
  122.     mtr[mtrx].m_size = size;
  123.     mtr[mtrx++].m_optimseg = OptimumSeg;
  124. #endif
  125.  
  126.     if (size == 0) return NULL;
  127.  
  128.     if (FarStorage == FALSE) {  /* use the local heap */
  129.     HANDLE hMem;
  130.  
  131.     if ((hMem = LocalAlloc (LMEM_FIXED, size)) != NULL) {
  132.         return (LPSTR)LocalLock (hMem);
  133.     }
  134.     else return NULL;
  135.     }
  136.  
  137.     /*-Attempt to suballocate from last used segment */
  138.     if (OptimumSeg) {
  139.     wSeg = HIWORD(OptimumSeg);
  140. #if MEMTRACE
  141.         mtr[mtrx].m_cnt = OptimumSeg->alloc_count;
  142. #endif
  143.     Block = SubAlloc (wSeg, size);
  144.     if (Block != NULL) {
  145.             ++(OptimumSeg->alloc_count);
  146.         return (char*)Block;     /* quick success ! */
  147.     }
  148.     }
  149.  
  150.     /*-Scan segment list, attempting to find one where suballocation is
  151.        possible */
  152.     Seg = &SegList;
  153.     for (;;) {
  154.     if (Seg->next == NULL) {
  155.         /*-initialize a new Segment and chain it on tail */
  156.         HANDLE      hSeg;
  157.         DWORD       SegSize;
  158.  
  159.         SegSize = max (MINSEGSIZE, HEAPOVH + SEGHEADOFFSET +
  160.                        sizeof(SEGHEADER) + (DWORD)size);
  161.         hSeg = GlobalAlloc (GMEM_MOVEABLE, SegSize);
  162.         if (hSeg == NULL) return (char*)NULL;  /* segment allocation
  163.                               failure */
  164.         SegSize = GlobalSize (hSeg);
  165.         wSeg = HIWORD(GlobalLock (hSeg));
  166.         LocalInit (wSeg, 0, SegSize - HEAPOFFSET);
  167.         GlobalUnlock (hSeg);
  168.         /* the segment remains locked once, due to LocalInit */
  169.  
  170.         SWITCH_DS(wSeg)
  171.         LockData (0);   /* this ensures the segment's selector will
  172.                    never change */
  173.         /* note that allocating a GMEM_FIXED segment would have been
  174.            cleaner but, in Windows 3.0, such segments also end up
  175.            being page-locked */
  176.         RESTORE_DS
  177.  
  178.         Seg->next = (SEGHEADER*)MAKELONG(SEGHEADOFFSET,wSeg);
  179.         Seg = Seg->next;
  180.         Seg->next = NULL;
  181.         Seg->alloc_count = 0;
  182.         NewSeg = TRUE;
  183. #if MEMTRACE
  184.     mtr[mtrx].m_func = MTR_MALLOCSEG;
  185.     mtr[mtrx].m_ptr.m_segh = Seg;
  186.     mtr[mtrx].m_cnt = Seg->alloc_count;
  187.     mtr[mtrx].m_size = SegSize;
  188.     mtr[mtrx++].m_optimseg = OptimumSeg;
  189. #endif
  190.     }
  191.     else {
  192.         Seg = Seg->next;
  193.         wSeg = HIWORD(Seg);
  194.     }
  195.         
  196.     if (Seg == OptimumSeg) continue;    /* skip this already tried
  197.                            one */
  198.     /*-try to allocate space in that segment */
  199. #if MEMTRACE
  200.         mtr[mtrx].m_cnt = Seg->alloc_count;
  201. #endif
  202.     Block = SubAlloc (wSeg, size);
  203.     if (Block != NULL) ++(Seg->alloc_count);
  204.     if ((Block != NULL) || NewSeg) {
  205.         OptimumSeg = Seg;   /* next malloc will try this segment
  206.                    first */
  207.         return (char*)Block;
  208.     }
  209.     }
  210. } /* malloc */
  211.  
  212. /* free:    frees an allocated block */
  213. /* =====                              */
  214.  
  215. void CDECL free (void *block)
  216. {
  217.     HANDLE  hSeg;
  218.     WORD    wSeg;
  219.     SEGHEADER *Seg;
  220.     HANDLE  hBlock;
  221. #if MEMTRACE
  222.     WORD    RealSize = 0;
  223. #endif
  224.  
  225.     if (FarStorage == FALSE) {  /* use the local heap */
  226.     HANDLE hMem;
  227.  
  228.     hMem = LocalHandle (LOWORD(block));
  229.     LocalUnlock (hMem);
  230.     LocalFree (hMem);
  231.     return;
  232.     }
  233.  
  234.     wSeg = HIWORD((DWORD)block);
  235.     hSeg = LOWORD(GlobalHandle (wSeg));
  236.  
  237.     SWITCH_DS(wSeg)
  238.     LocalUnlock (hBlock = LocalHandle (LOWORD(block)));
  239. #if MEMTRACE
  240.     RealSize = LocalSize (hBlock);
  241. #endif
  242.     LocalFree (hBlock);
  243.     RESTORE_DS
  244.  
  245.     Seg = (SEGHEADER *)(MAKELONG(SEGHEADOFFSET,HIWORD(block)));
  246. #if MEMTRACE
  247.     mtr[mtrx].m_func = MTR_FREE;
  248.     mtr[mtrx].m_ptr.m_block = block;
  249.     mtr[mtrx].m_cnt = Seg->alloc_count;
  250.     mtr[mtrx].m_size = RealSize;
  251.     mtr[mtrx++].m_optimseg = OptimumSeg;
  252. #endif
  253.     if (--(Seg->alloc_count) == 0) {  /* this segment is no longer used!
  254.                      Let's get rid of it */
  255.         SEGHEADER   *sp;
  256.  
  257.         if (Seg == OptimumSeg) OptimumSeg = NULL;
  258.         sp = &SegList;
  259.         while (sp->next != Seg) {
  260.             sp = sp->next;
  261.             if (sp == NULL) {   /* this segment is not in the list!!! */
  262.                 /* this should not happen, but you never know... */
  263.                 static BOOL WarningDisplayed = FALSE;
  264.  
  265.                 if (!WarningDisplayed) {
  266.             MessageBox (hFrameWnd,
  267.                                 "Please shutdown EMACS as soon as possible",
  268.                                 "Corrupted memory",
  269.                                 MB_OK | MB_ICONSTOP);
  270.                 }
  271.                 WarningDisplayed = TRUE;
  272.                 return;
  273.             }
  274.         }
  275.         sp->next = Seg->next;       /* unlink the segment */
  276. #if MEMTRACE
  277.         mtr[mtrx].m_func = MTR_FREESEG;
  278.         mtr[mtrx].m_ptr.m_segh = Seg;
  279.         mtr[mtrx].m_cnt = Seg->alloc_count;
  280.         mtr[mtrx].m_size = GlobalSize (hSeg);
  281.         mtr[mtrx++].m_optimseg = OptimumSeg;
  282. #endif
  283.  
  284.         SWITCH_DS(wSeg)
  285.     UnlockData (0);
  286.     RESTORE_DS
  287.     
  288.         GlobalUnlock (hSeg);
  289.         GlobalFree (hSeg);          /* and release it */
  290.     }
  291.     else {  /* segment still in use */
  292.     OptimumSeg = Seg;       /* next malloc will try this segment
  293.                    first */
  294.     }
  295. } /* free */
  296.  
  297. /* realloc: reallocates a chunk of memory (shrink or expand) */
  298. /* ========                                                   */
  299.  
  300. void * CDECL realloc(void * oldblock, size_t size);
  301. {
  302.     HANDLE  hBlock, hOldBlock;
  303.     void    *Block;
  304.     WORD    wSeg;
  305.     int     OldSize;
  306. #if MEMTRACE
  307.     WORD    RealSize = 0;
  308. #endif
  309.  
  310.     if (oldblock == NULL) return malloc (size);
  311.     
  312.     if (FarStorage == FALSE) {  /* use the local heap */
  313.     HANDLE hMem;
  314.  
  315.     hMem = LocalHandle (LOWORD(oldblock));
  316.     LocalUnlock (hMem);
  317.     if ((hMem = LocalReAlloc (hMem, LMEM_MOVEABLE, size)) != NULL) {
  318.         return (LPSTR)LocalLock (hMem);
  319.     }
  320.     else return NULL;
  321.     }
  322.  
  323.     wSeg = HIWORD(oldblock);
  324.  
  325.     SWITCH_DS(wSeg)
  326.     LocalUnlock (hOldBlock = LocalHandle (LOWORD(oldblock)));
  327.     OldSize = LocalSize (hOldBlock);
  328.     hBlock = LocalReAlloc (hOldBlock, size, LMEM_MOVEABLE | LMEM_NOCOMPACT);
  329.     if (hBlock) {
  330.     Block = (LPSTR)LocalLock (hBlock);
  331. #if MEMTRACE
  332.     RealSize = LocalSize (hBlock);
  333. #endif
  334.     }
  335.     else oldblock = LocalLock (hOldBlock); 
  336.     RESTORE_DS
  337. #if MEMTRACE
  338.     mtr[mtrx].m_func = MTR_REALLOC;
  339.     mtr[mtrx].m_ptr.m_block = hBlock ? Block : NULL;
  340.     mtr[mtrx].m_cnt = ((SEGHEADER *)(MAKELONG(SEGHEADOFFSET,wSeg)))->alloc_count;
  341.     mtr[mtrx].m_size = RealSize;
  342.     mtr[mtrx++].m_optimseg = OptimumSeg;
  343. #endif
  344.     
  345.     if (hBlock) return Block;
  346.     else {  /* we have to malloc, possibly into another segment, and
  347.            copy the data over */
  348.         if ((Block = malloc (size)) != NULL) {
  349.             _fmemcpy (Block, oldblock, min(size, OldSize));
  350.         free (oldblock);
  351.         }
  352.         return Block;
  353.     }
  354. } /* realloc */
  355. #endif  /* SUBALLOC */
  356. /* InitializeFarStorage:    start the suballocation mechanism */
  357. /* ====================                                       */
  358.  
  359. void FAR PASCAL InitializeFarStorage (void)
  360. {
  361. #if SUBALLOC
  362.     FarStorage = TRUE;
  363. #endif
  364. } /* InitializeFarStorage */
  365.  
  366. /* JettisonFarStorage: Release all the global segments (quitting time) */
  367. /* ==================                                                  */
  368.  
  369. void FAR PASCAL JettisonFarStorage (void)
  370. {
  371. #if SUBALLOC
  372.     SEGHEADER   *sp;
  373.     HANDLE      hSeg;
  374.  
  375.     sp = SegList.next;
  376.     while (sp != NULL) {
  377.     hSeg = LOWORD(GlobalHandle (HIWORD((DWORD)sp)));
  378.     sp = sp->next;
  379.         GlobalUnlock (hSeg);
  380.         GlobalFree (hSeg);
  381.     }
  382.     FarStorage = FALSE;
  383. #endif
  384. } /* JettisonFarStorage */
  385.